import copy
import urwid
import stats


class Text(object):
    UPTIME = "Uptime: {0}, Firebird uptime: {1}"
    
    ATTACHMENTS = "Attachments: {0}, Attachments/min: {1}"
    FILE_HANDLES = "File handles: "
    TX_PER_MIN = "Tx/min: "
    
    FOOTER = "(q)uit"

class DatabaseColumn(object):
    def __init__(self, humanName, propertyName, weight = 1):
        self.humanName = humanName
        self.propertyName = propertyName
        self.weight = weight
    
class DatabaseListWalker(urwid.ListWalker):
    
    def __init__(self, databases, columns):
        self._databases = databases;
        self._databaseRows = dict()
        self.focus = 0
        self.columns = columns
        
    def get_focus(self):
        return self._getAtPos(self.focus)
    
    def set_focus(self, focus):
        self.focus = focus
        self._modified()
    
    def get_next(self, startFrom):
        return self._getAtPos(startFrom + 1)
    
    def get_prev(self, startFrom):
        return self._getAtPos(startFrom - 1)
    
    def _getAtPos(self, position):
        if position < 0 or position >= len(self._databases):
            return None, None
        
        currentDbRow = None
        if position in self._databaseRows.keys():
            currentDbRow = self._databaseRows[position]
        else:
            database = self._databases[position]
            columnValues = []
            for column in self.columns:
                attVal = str(getattr(database, column.propertyName))
                columnVal = ('weight', column.weight, urwid.Text(attVal, align = 'center'))
                columnValues.append(columnVal)
                
            currentDbRow = urwid.Columns(columnValues)
            self._databaseRows[position] = currentDbRow
        
        return currentDbRow, position
    
    def invalidate(self):
        self._databaseRows = dict()
        self._modified()

class DatabaseListBox(urwid.WidgetWrap):

    _DEFAULT_COLUMNS = [DatabaseColumn("DATABASE", "path", 5), \
                        DatabaseColumn("ATT", "attachmentCount"), \
                        DatabaseColumn("ATT_M", "attachmentsPerMin"), \
                        DatabaseColumn("TX_M", "transactionsPerMinute"), \
                        DatabaseColumn("OIT_G", "oitGap"), \
                        DatabaseColumn("OAT_G", "oatGap"), \
                        DatabaseColumn("OST_G", "ostGap")]
    
    def __init__(self, databases):
        self.selectedColumns = copy.deepcopy(DatabaseListBox._DEFAULT_COLUMNS)
        headerColumns = []
        for column in self.selectedColumns:
            headerColVal = ('weight', column.weight, urwid.Text(column.humanName, align = 'center'))
            headerColumns.append(headerColVal)
        self.headerRow = urwid.AttrMap(urwid.Columns(headerColumns), 'dbColHeader')
       
        self.listWalker = DatabaseListWalker(databases, self.selectedColumns)
        
        listbox = urwid.ListBox(self.listWalker)
        self.body = urwid.Frame(listbox, header = self.headerRow)
        urwid.WidgetWrap.__init__(self, self.body)
 
    def invalidate(self):
        self.listWalker.invalidate()

class OverallStats(urwid.WidgetWrap):
    
    def __init__(self, server):
        self.server = server
        self.localStats = server.localStats
        
        self.body = urwid.Pile([urwid.Text('?'), urwid.Text('?')])
        self.invalidate()
        urwid.WidgetWrap.__init__(self, self.body)
    
    def invalidate(self):
        
        (uptimeText, options) = self.body.contents[0]
        uptimeText.set_text(Text.UPTIME.format(self.localStats.uptime, self.localStats.firebirdUptime))
        (attachCountText, options) = self.body.contents[1]
        attachCountText.set_text(Text.ATTACHMENTS.format(self.server.attachmentCount, self.server.attachmentsPerMin))
        
        
class Ui(object):
    
    _PALETTE = [('body', urwid.WHITE, urwid.BLACK), ('dbColHeader', urwid.BLACK, urwid.DARK_GREEN)]
    
    def exitOnQ(self, textInput):
        if textInput in ('q', 'Q'):
            self.server.disconnect()
            raise urwid.ExitMainLoop()
    
    def update(self, main_loop, user_data):
        self.server.poll()
        self.listbox.invalidate()
        self.overallStats.invalidate()
        self.loop.set_alarm_in(2.5, self.update)
        
    def __init__(self, serverName, user, password):
        self.server = stats.Server(serverName, user, password)

        self.overallStats = OverallStats(self.server)
        
        self.listbox = DatabaseListBox(self.server.databases)
        footer = urwid.Text(Text.FOOTER)
        self.dbFrame = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), footer = footer)
        
        body = urwid.Pile([('flow', self.overallStats), self.dbFrame])
        
        self.loop = urwid.MainLoop(body, palette = Ui._PALETTE, unhandled_input = self.exitOnQ)
        
    def run(self):
        self.server.poll()
        self.loop.set_alarm_in(2.5, self.update)
        self.loop.run()
        